package com.orange.adminapi.security.provider;

import cn.hutool.core.util.StrUtil;
import com.orange.core.security.token.AdminAuthenticationToken;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;

@Slf4j
@RequiredArgsConstructor
public class AdminAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailsService;
    private final PasswordEncoder passwordEncoder;

    protected UserDetails retrieveUser(String username) throws AuthenticationException {
        UserDetails user;
        try {
            user = userDetailsService.loadUserByUsername(username);
            if (user == null) {
                throw new UsernameNotFoundException(String.format("账号 %s 不存在", username));
            }
        } catch (UsernameNotFoundException e) {
            log.error("账号不存在");
            throw new UsernameNotFoundException("账号不存在", e);
        }
        return user;
    }

    protected void preAuthenticationChecks(Authentication authentication) {
        if (StrUtil.isBlank(authentication.getName())) {
            throw new BadCredentialsException("请输入账号");
        }
        if (authentication.getCredentials() == null) {
            throw new BadCredentialsException("密码不能为空");
        }
    }

    protected void additionalAuthenticationChecks(Authentication authentication, UserDetails userDetails) throws AuthenticationException {
        if (!userDetails.isAccountNonLocked()) {
            throw new LockedException(String.format("当前账号 %s 已锁定", userDetails.getUsername()));
        }
        if (!userDetails.isEnabled()) {
            throw new DisabledException(String.format("当前账号 %s 已禁用", userDetails.getUsername()));
        }
        if (!userDetails.isAccountNonExpired()) {
            throw new AccountExpiredException(String.format("当前账号 %s 已过期", userDetails.getUsername()));
        }
        String presentedPassword = authentication.getCredentials().toString();
        if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
            throw new BadCredentialsException("用户名/密码不正确");
        }
    }

    protected void postAuthenticationChecks(UserDetails userDetails) {
        if (!userDetails.isCredentialsNonExpired()) {
            throw new CredentialsExpiredException("当前帐号密码已过期");
        }
    }

    protected Authentication createSuccessAuthentication(UserDetails userDetails, Authentication authentication) {
        return new AdminAuthenticationToken(userDetails, authentication.getCredentials(), ((AdminAuthenticationToken) authentication).getRememberMe(), userDetails.getAuthorities());
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        preAuthenticationChecks(authentication);
        UserDetails userDetails = retrieveUser(authentication.getName());
        additionalAuthenticationChecks(authentication, userDetails);
        postAuthenticationChecks(userDetails);
        return createSuccessAuthentication(userDetails, authentication);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return AdminAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
